package com.mq.mqserver.core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mq.common.ConsumerEnv;
import lombok.Data;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 创建 队列属性
 */
@Data
public class MSGQueue {
    //队列名称,队列的唯一属性
    private String name;
    //是否持久化
    private boolean durable = false;
    //是否独占
    private boolean exclusive = false;
    //是否自动删除
    private boolean autoDelete = false;
    //其他参数
    private Map<String,Object> args = new HashMap<>();

    //此处再添加一个属性:订阅该队列的消费者集合
    private List<ConsumerEnv> consumerEnvList = new ArrayList<>();
    //为了实现消费者轮训消费消息,再添加一个属性,记录当前轮到那个消费者消费消息了
    //这里使用AtomicInteger类来实现,目的是不让手动修改,且要实现自增的功能
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    //添加一个新的订阅者(消费者)
    public void addConsumerEnv(ConsumerEnv consumerEnv){
        consumerEnvList.add(consumerEnv);
    }

    //挑选一个订阅者,消费当前消息,按照轮训的方式
    public ConsumerEnv chooseConsumerEnv(){
        if(consumerEnvList.isEmpty()){
            //当前该队列还没有消费者订阅
            System.out.println("[MSGQueue] 当前该队列没有订阅者");
            return null;
        }
        //按照轮训的方式获取一个要消费消息的订阅者下标
        int index = atomicInteger.get()%consumerEnvList.size();
        //让轮训值 自增
        atomicInteger.getAndIncrement();
        return consumerEnvList.get(index);
    }

    //这里的get set为了和数据库中数据类型匹配
    //为了和数据库对应,获取数据的时候,要将Map转换为字符串
    //读取数据的时候,再将数据库中的字符串转换为Map类型
    public String getArgs(){
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            //将HashMap转换为String类型
            return objectMapper.writeValueAsString(args);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
//            throw new RuntimeException(e);
        }
        return "{}";
    }

    public void setArgs(String args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        //              将字符串转换为HashMap类型,若转换为基本数据类型时直接填就行,
        //              这里转换的是HashMap集合类型,比较复杂,需要借助匿名内部类TypeReference类实现
        this.args = mapper.readValue(args,new TypeReference<HashMap<String,Object>>(){});
    }

    //这一对set get方法是用在java代码中使用的,如测试用例的,上面的一组是针对数据库使用的
    public Object getArgs(String key){
        return args.get(key);
    }
    public void setArgs(String key,Object val){
        args.put(key,val);
    }
    public void setArgs(Map<String,Object> args){
        this.args = args;
    }
}
